﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Diagnostics;
using System.Collections;
using System.Windows.Forms;
using System.Text.RegularExpressions;

namespace Buccontrols
{
    public enum OptionFunction { name, text, number, array, action, end }

    public static class Options
    {
        #region Initialize

        public static void Initialize()
        {
            rescNames = new List<string>();
            rescContent = new List<object>();
            shownCommentTypes = new List<string>();
            environmentVars = new Dictionary<string, string>();
            debugmode = false;
            font = new Font("SansSerif", 12.0f);
            layoutFolder = Application.StartupPath  + @"\Layout";
            pluginsFolder = Application.StartupPath + @"\Plugins";
            startupPlugin = "FileBrowser";

            LoadEnvironmentVariables();
        }

        #endregion

        #region Private attributes

        static Font font;
        static String layoutFolder;
        static String pluginsFolder;
        static String startupPlugin;
        static List<object> rescContent;
        static List<string> rescNames;
        static List<string> shownCommentTypes;
        static Dictionary<string, string> environmentVars;
        static bool debugmode;
        static OptionsCollection options;

        #endregion

        #region Public attributes

        public static OptionsCollection Settings
        {
            get { return options; }
        }

        public static Font Font
        {
            get
            {
                try
                {
                    string floatstr = options.Get("BuccOptions.Font.Size").Value;
                    floatstr = Regex.Match(floatstr, @"[0-9]+\.{0,1}[0-9]*").Value;
                    float floatval = float.Parse(floatstr);
                    font = new Font(options.Get("BuccOptions.Font.Family").Value, floatval);
                }
                catch
                {
                }
                return font;
            }
        }

        public static String LayoutFolder
        {
            get
            {
                try
                {
                    string layoutFolderStr = options.Get("BuccOptions.LayoutFolder").Value;
                    if (layoutFolderStr != "not found!") layoutFolder = layoutFolderStr;
                }
                catch { }
                return layoutFolder + "\\";
            }
        }

        public static string PluginsFolder
        {
            get
            {
                try
                {
                    string pluginsFolderStr = options.Get("BuccOptions.PluginsFolder").Value;
                    if (pluginsFolderStr != "not found!") layoutFolder = pluginsFolderStr;
                }
                catch { }
                return pluginsFolder + "\\";
            }
        }

        public static List<string> ShownCommentTypes
        {
            get { return shownCommentTypes; }
            set { shownCommentTypes = value; }
        }

        #endregion

        #region Private Functions

        #endregion

        #region Public Functions

        public static void LoadImage(string name, string path)
        {
            Options.WriteComment("(i) Loading image " + name);
            rescNames.Add(name);
            rescContent.Add(Image.FromFile(path));
        }

        public static void AddResource(string name, object resc)
        {
            rescNames.Add(name);
            rescContent.Add(resc);
        }

        public static object GetResource(string name)
        {
            int index = rescNames.IndexOf(name);
            if (index == -1)
            {
                Options.WriteComment("(!) Resource not found!");
                return null;
            }

            try
            {
                Options.WriteComment("(d) returned resource: " + name);
                return rescContent[index];
            }
            catch (Exception)
            {
                Options.WriteComment("(!) Something went wrong!");
            }
            return null;
        }

        public static void LoadImageDirectory(string directory)
        {
            FileInfo[] files = (new DirectoryInfo(directory)).GetFiles();
            foreach (FileInfo file in files)
            {
                LoadImage(file.Name.Split('.')[0], file.FullName);
            }
        }

        public static bool WriteComment(string info)
        {
            try
            {
                if (info.Length > 3 && shownCommentTypes.Contains(info.Substring(0, 4)))
                    Console.WriteLine(info);
                else if (debugmode)
                    Debug.WriteLine(info);
                else return false;
                return true;
            }
            catch (Exception)
            {
                Console.WriteLine("(*) " + info);
                return false;
            }
        }

        public static void SaveOptions()
        {
            
        }

        public static void LoadEnvironmentVariables()
        {
            environmentVars = new Dictionary<string, string>();
            environmentVars.Add("BuccPath", Application.StartupPath);
        }

        public static void LoadOptions()
        {
            StreamReader sr = new StreamReader(Environment.CurrentDirectory + @"\Options.bucc.opt");
            string readLine = sr.ReadToEnd(), 
                line = "",
                name = "",
                array = "",
                varname = "";
            OptionsCollection currentOC = new OptionsCollection("error");
            OptionFunction function = OptionFunction.name,
                lastFunction = OptionFunction.end;
            List<string> terms = new List<string>();
            List<OptionFunction> funcs = new List<OptionFunction>();
            bool inQuote = false,
                inVarName = false;
            for (int i = 0; i < readLine.Length; i++)
            {
                switch (readLine[i])
                {
                    case '"':
                        inQuote = !inQuote;
                        break;
                    case '\\':
                        i++;
                        goto default;
                    case '[':
                        i++;
                        inVarName = true;
                        goto default;
                    case ']':
                        inVarName = false;
                        try
                        {
                            line += environmentVars[varname];
                        }
                        catch
                        {
                            line += "[" + varname + "]";
                            Options.WriteComment("(!) Environment Variable not found: " + varname);
                        }
                        varname = "";
                        break;
                    case ' ':
                        if (inQuote) goto default;
                        break;
                    case ':':
                        if (lastFunction == OptionFunction.name)
                            currentOC = currentOC.Add(name, name);
                        terms.Add(line);
                        funcs.Add(OptionFunction.name);
                        name = line;
                        if (name == "BuccOptions")
                            currentOC = new OptionsCollection("BuccOptions");
                        lastFunction = OptionFunction.name;
                        //currentOC = new OptionsCollection(name);
                        function = OptionFunction.number;
                        line = "";
                        break;
                    case ',':
                        function = OptionFunction.array;
                        lastFunction = OptionFunction.array;
                        array = array == "" ? line : array + "," + line;
                        terms.Add(line);
                        funcs.Add(function);
                        line = "";
                        break;
                    case ';':
                        if (lastFunction == OptionFunction.end)
                            currentOC = currentOC.Parent;
                        if (line == "") break;
                        terms.Add(line);
                        funcs.Add(function);
                        switch (function)
                        {
                            case OptionFunction.action:
                                currentOC = currentOC.Add(name, line);
                                break;
                            case OptionFunction.array:
                                currentOC = currentOC.Add(name, array + "," + line);
                                break;
                            case OptionFunction.name:
                                currentOC = currentOC.Add(name, line);
                                break;
                            case OptionFunction.number:
                                currentOC = currentOC.Add(name, line);
                                break;
                            case OptionFunction.text:
                                currentOC = currentOC.Add(name, line);
                                break;
                        }
                        function = OptionFunction.name;
                        lastFunction = OptionFunction.end;
                        currentOC = currentOC.Parent;
                        line = "";
                        array = "";
                        break;
                    case '\n':
                    case '\r':
                        if (inQuote) goto default;
                        break;
                    default:
                        if (!"0123456789".Contains(readLine[i]) && function == OptionFunction.number)
                            function = OptionFunction.text;
                        if (inVarName)
                            varname = varname.Insert(varname.Length, readLine[i].ToString());
                        else
                            line = line.Insert(line.Length, readLine[i].ToString());
                        break;
                }
            }

            if (currentOC.Parent != null)
            {
                Options.WriteComment("(!) Error in optionsfile: not enough semicolons encountered.");
                while (currentOC.Parent != null)
                    currentOC = currentOC.Parent;
            }

            debugmode = currentOC.Get("BuccOptions.DebugMode").Value.Equals("true", StringComparison.OrdinalIgnoreCase);
            shownCommentTypes = currentOC.Get("BuccOptions.ShowCommentTypes").Value.Split(',').ToList<string>();
            options = currentOC;
        }

        #endregion
    }
}
